package main

import (
	"flag"
	"fmt"
	"net/http"
	"net/url"
	"os"
	"os/signal"
	"path"
	"strconv"
	"strings"
	"syscall"
	"time"

	LRUCache "github.com/hashicorp/golang-lru"
	"github.com/mr-tron/base58"
)

type Handlers struct {
	w http.ResponseWriter
	r *http.Request
}

var lrucache *LRUCache.Cache
var (
	eport       int    = 16666
	networkType string = "ct" //中国电信
	cacheMax    int64  = 1
)
var DATABASE *DB

const (
	InfoColor    = "\033[1;34m%s\033[0m \n"
	NoticeColor  = "\033[1;36m%s\033[0m \n"
	WarningColor = "\033[1;33m%s\033[0m \n"
	ErrorColor   = "\033[1;31m%s\033[0m \n"
	DebugColor   = "\033[0;36m%s\033[0m \n"
	ProxyRouter  = "proxy"
)

/*代理http函数*/
func (server Handlers) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	var method = r.Method
	server.w = w
	server.r = r
	switch method {
	case "GET":
		server.Handle() //处理get方式
	default:
		w.WriteHeader(500)
	}
}

func (server Handlers) Handle() {
	urlpath := server.r.URL.Path
	base58url := urlpath[1:]
	var isProxyRouter bool
	var fname string
	var chk string
	p := strings.Split(base58url, "/")
	if len(p) == 2 && p[0] == ProxyRouter {
		isProxyRouter = true
		ext := path.Ext(p[1])
		b58url := strings.TrimSuffix(p[1], ext)
		c, err := base58.Decode(b58url)
		if err != nil {
			fmt.Printf("Demo %v, got error %s\n", c, err)
			server.w.WriteHeader(500)
			return
		}
		bs58c := path.Base(string(c))
		cc, errs := base58.Decode(bs58c)
		if errs != nil {
			fmt.Printf("Demo %v, got error %s\n", cc, err)
			server.w.WriteHeader(500)
			return
		}
		uu, _ := url.Parse(string(cc))
		fname = strings.TrimSuffix(uu.Path, ext)
		chk = string(c) + ext
	} else {
		isProxyRouter = false
		base58url = strings.Split(base58url, ".")[0]

		num, err := base58.Decode(base58url)
		if err != nil {
			fmt.Printf("Demo %v, got error %s\n", base58url, err)
			server.w.WriteHeader(500)
			return
		}
		chk = string(num)
	}
	var chkpath string
	u, err := url.Parse(chk)
	if err == nil {
		chkpath = u.Path
	} else {
		fmt.Printf("Demo %v, got error %s\n", base58url, err)
		server.w.WriteHeader(500)
		return
	}
	if strings.HasPrefix(chk, "http") == false {
		fmt.Printf("error url sechma %s\n", chk)
		server.w.WriteHeader(500)
		return
	}
	// chk := base58.Encode(num)
	if strings.HasSuffix(chkpath, ".mp4") {
		h := NewRangeHandle(server.w, server.r, chk, isProxyRouter, fname)
		h.Handle()
	} else if strings.HasSuffix(chkpath, ".ts") {
		if strings.Contains(u.Host, "xnxx-cdn") == true {
			h := NewBlockHandle(server.w, server.r, chk)
			h.Handle()
		} else {
			h := NewTSHandle(server.w, server.r, chk)
			h.Handle()
		}

	} else if strings.HasSuffix(chkpath, ".m3u8") {
		h := NewM3U8Handle(server.w, server.r, chk)
		h.Handle()
	} else {
		h := NewBlockHandle(server.w, server.r, chk)
		h.Handle()
	}
}

func main() {
	//创建监听退出chan
	c := make(chan os.Signal)
	//监听指定信号 ctrl+c kill
	signal.Notify(c, syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGUSR1, syscall.SIGUSR2)
	go func() {
		for s := range c {
			switch s {
			case syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT:
				fmt.Println("退出", s)
				ExitFunc()
			case syscall.SIGUSR1:
				fmt.Println("usr1", s)
			case syscall.SIGUSR2:
				fmt.Println("usr2", s)
			default:
				fmt.Println("other", s)
			}
		}
	}()
	flag.StringVar(&networkType, "n", "ct", "网络类型")
	flag.IntVar(&eport, "p", 16666, "端口设置")
	flag.Int64Var(&cacheMax, "d", 1, "缓存容量")
	flag.Parse()
	fmt.Println("打印网络类型", networkType)
	if eport > 65535 || eport < 100 {
		fmt.Println("端口不正确")
		os.Exit(0)
	}
	cacheMax = cacheMax * 1024 * 1024 * 1024 //单位GB
	MakeCacheDir()
	go SetUPnP()
	go jobs()
	lrucache, _ = LRUCache.New(200)
	RangeInit()
	DATABASE = InitDB()
	var server Handlers
	http.Handle("/", server)
	err := http.ListenAndServe(":"+strconv.Itoa(eport), nil)
	if err != nil {
		fmt.Println(err)
	}
}
func jobs() {
	mac := GetMACAddress()
	fmt.Println(mac)
	ID := SHA1(mac)
	clearTicker := time.NewTicker(10 * time.Minute)
	pingTicker := time.NewTicker(10 * time.Second)
	for {
		select {
		case <-clearTicker.C:
			ClearCache()
		case <-pingTicker.C:
			Ping(ID)
		}
	}
}

func ExitFunc() {
	fmt.Println("开始退出...")
	fmt.Println("执行清理...")
	fmt.Println("结束退出...")
	os.Exit(0)
}

// func (server *Handlers) download(w http.ResponseWriter, r *http.Request) {
// 	query := r.PostFormValue("data")
// 	w.Header().Set("Access-Control-Allow-Origin", "*")
// 	if query == "" {
// 		w.Write([]byte("{code: 300, msg: \"param_error\"}"))
// 		return
// 	}
// 	h := NewDownloadHandle(server.w, server.r, query)
// 	h.Handle()
// }

// func (server *Handlers) isExist(w http.ResponseWriter, r *http.Request) {
// 	id := r.PostFormValue("id")
// 	w.Header().Set("Access-Control-Allow-Origin", "*")
// 	if id == "" {
// 		w.Write([]byte("{code: 300, msg: \"param_error\"}"))
// 		return
// 	}
// 	_, err := os.Stat("./download/" + id + ".mp4")
// 	var isFile bool
// 	if err == nil {
// 		isFile = true
// 	} else {
// 		isFile = false
// 	}
// 	m := make(map[string]interface{})
// 	m["code"] = 200
// 	m["data"] = isFile
// 	mjson, _ := json.Marshal(m)
// 	w.Write([]byte(mjson))
// }

// func (server *Handlers) listen() {
// 	http.HandleFunc("/downloadVideo", server.download)
// 	http.HandleFunc("/isExist", server.isExist)
// 	fsh := http.FileServer(http.Dir("./download"))
// 	http.Handle("/static/", http.StripPrefix("/static/", fsh))
// }
